﻿package com.dg.gaming.api.common {
    import com.dg.gaming.api.common.msg.ITransmittable;
    import com.dg.gaming.api.common.playerstate.*;
    import com.dg.gaming.api.common.util.*;
    import com.dg.gaming.api.common.msg.*;
    import nanoxml.XMLElement;

    /**
     * ...
     * @author
     */
    public class Player extends Observable implements ITransmittable {
        /** Constant to show that a player hasn't been seated. */
        public static const NOT_SEATED:int = -1;

        public static const XML_ATT_NAME:String = "name";

        public static const XML_ATT_STATE:String = "state";

        public static const XML_ATT_SEAT:String = "seat";


        /** Username of the user. */
        protected var _playerId:Number;

        /**
         * Seat number of the user e.g. in chess, 0=White, 1=Black. NOT_SEATED (-1)
         * indicates that the Player hasn't sat down yet.
         */
        protected var _seatNum:int;

        /**
         * State of the player.  The playerState can either be seated, viewing,
         * ready etc.  If a Player is in the viewing state for example this variable
         * will be an instance of the PlayerStateViewing class (state design pattern).
         */
        protected var _playerState:PlayerState; // State of the player

        /**
         * The user that this player is representing
         */
        protected var _theUser:User = null;

        /**
         * The name of user
         */

        protected var _username:String;

        /**
         * Constructor requires both a player and a status as parameters and sets
         * the seat number to NOT_SEATED.
         *
         * @param playerName   Name of player
         * @param playerState  State of the player
         */

        public function init(theUser:User, playerState:PlayerState):void {
            this._theUser = theUser;
            this._playerId = theUser.userid;
            this._playerState = playerState;
            this._seatNum = NOT_SEATED;
        }

        /**
         * Constructor which creates a Player object from the flatten () method of
         * another Player object.
         *
         * @param  message    XML element version of object.
         */
        public function initXML(message:XMLElement):void {
            this._theUser = null;
            this._playerId = message.getLongAttribute(XML_ATT_NAME);
            this._playerState = PlayerStateFactory.getState(message.getStringAttribute(XML_ATT_STATE));
            this._seatNum = message.getIntAttribute(XML_ATT_SEAT);
            this._username = message.getStringAttribute(User.XML_ATT_USERNAME);
        }


        public function get playerId():Number {
            return _playerId;
        }

        public function set playerId(value:Number):void {
            _playerId = value;
        }

        public function get seatNum():int {
            return _seatNum;
        }

        /**
         * Set the seat number of this player (set when a player sits down).
         *
         * @param seatNum  Integer >= 0 and < maximum number of seats.
         */

        public function set seatNum(value:int):void {
            _seatNum = value;
            // Notify observers
            setChanged();
            notifyObservers();

        }


        public function get theUser():User {
            return _theUser;
        }

        public function get username():String {
            return _username;
        }

        public function get playerState():PlayerState {
            return _playerState;
        }

        /**
         * Set the seat number of this player (set when a player sits down).
         *
         * @param seatNum  Integer >= 0 and < maximum number of seats.
         */
        public function set playerState(value:PlayerState):void {
            _playerState = value;
            // Notify observers
            setChanged();
            notifyObservers();
        }

        public function set theUser(value:User):void {
            _theUser = value;
        }

        /**
         * Player sits down at a table.
         */
        public function sit():void {
            // change state
            _playerState = playerState.sit();

            // Notify observers
            setChanged();
            notifyObservers();
        }

        /**
         * Transmittable String representation of this object (XML).
         *
         * @see com.dg.gaming.api.common.msg.ITransmittable#flatten()
         */
        public function flatten():XMLElement {
            var message:XMLElement = new XMLElement;
            message.name = Msg.PLAYER;
            message.setLongAttribute(XML_ATT_NAME, playerId);
            message.setAttribute(XML_ATT_STATE, playerState.stringValue());
            message.setIntAttribute(XML_ATT_SEAT, seatNum);
            return message;
        }

        public function flattenWithUser():XMLElement {
            var message:XMLElement = flatten();
            if (theUser != null) {
                message.setAttribute(User.XML_ATT_USERNAME, _theUser.username);
            }
            return message;
        }

        /**
         * Player stands up from a table.
         */
        public function stand():void {
            // change state
            _playerState = playerState.stand();
            _seatNum = NOT_SEATED;

            // Notify observers
            setChanged();
            notifyObservers();
        }

        /**
         * Player decides to start.
         */
        public function start():void {
            // change state
            _playerState = playerState.start();

            // Notify observers
            setChanged();
            notifyObservers();
        }

        /**
         * Return true if a player can sit or not.
         *
         * @param table      Link to table
         * @return         True if player can sit down.
         */
        public function canSit(table:Table):Boolean {
            // return state
            return playerState.canSit(table);
        }

        /**
         * Returns true if a player can stand.
         *
         * @param table      Link to table
         * @return           True if player can stand up.
         */
        public function canStand(table:Table):Boolean {
            // return state
            return playerState.canStand(table);
        }

        /**
         * Returns true if a player can start.
         *
         * @param table      Link to table.
         * @param game       Link to the game.
         * @return           True if player can start.
         */
        public function canStart(table:Table, game:Game):Boolean {
            // return state
            return playerState.canStart(table, game);
        }

        /**
         * Return if it a player can offer a draw or resign a game.
         *
         * @return  True if player can offer draw / resign.
         */
        public function canOfferDrawResign():Boolean {
            // return state
            return playerState.canOfferDrawResign();
        }





        /**
         * Returns the status of this player as a String.
         *
         * @return  Get the status of the player as a String.
         */
        public function getStatusStr():String {
            var str:String;
            // If the status is VIEWING then the player isn't playing
            if (playerState is PlayerStateViewing) {
                str = DGLabels.getInstance().getValue("not.playing");
            } else {
                str = GameLabels.getPlayerLabel(seatNum);
            }

            // Return the string wrapped with brackets
            return "(" + str + ")";
        }

        /**
         * String representation of this player.
         *
         * @see java.lang.Object#toString()
         */
        public override function toString():String {
            return toUserName();
        }

        public function toUserName():String {
            if (theUser != null) {
                return theUser.username;
            } else if (username != null) {
                return username;
            }
            return playerId + "";
        }

        /**
         * Returns the state of this player as a PlayerState object.
         *
         * @return     Return the state of the player.
         */
        public function getState():PlayerState {
            // return state
            return playerState;
        }

        /**
         * Return true if this player is viewing.
         *
         * @return  True if player state is PlayerStateViewing.
         */
        public function isViewing():Boolean {
            return (getState() is PlayerStateViewing);
        }

        /**
         * Return true if this player is seated.
         *
         * @return  True if player state is PlayerStateSeated.
         */
        public function isSeated():Boolean {
            return (getState() is PlayerStateSeated);
        }

        /**
         * Return true if this player is ready.
         *
         * @return  True if player state is PlayerStateReady.
         */
        public function isReady():Boolean {
            return (getState() is PlayerStateReady);
        }

        /**
         * Return true if this player is playing.
         *
         * @return  True if player state is PlayerStateGameStarted.
         */
        public function isPlaying():Boolean {
            return (getState() is PlayerStateGameStarted);
        }

    }

}